package com.young4j.springdemo.controller;

import com.young4j.springdemo.config.redis.RedisAtomicClient;
import com.young4j.springdemo.config.redis.RedisLock;
import com.young4j.springdemo.config.redis.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author yf
 * @Date 2018/12/29 17:44
 **/
@RestController
@RequestMapping("/redis")
public class RedisController {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private RedisTemplate redisTemplate;
    /*
    @Autowired
    private StringRedisTemplate stringRedisTemplate;*/
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisUtil redisUtil;
    private static final String STRING_PREFIX = "STRING.KEY";
    private static final String STRING_KEY = "string.key.key1";
    private static final String STRING_VALUE = "string.key.value1";
    private static final String STRING_NUM_KEY = "string.num.key.key1";
    private static final String STRING_NUM_VALUE = "1";
    /** -----------------springboot redis 配置测试开始----------------- */
    /*@RequestMapping("/redisTemplate")
    public Object redisTemplate(){
        redisTemplate.opsForValue().set("redisTemplate","redisTemplate");
        Object ret = redisTemplate.opsForValue().get("redisTemplate");
        return ret;
    }
    @RequestMapping("/stringRedisTemplate")
    public Object stringRedisTemplate(){
        stringRedisTemplate.opsForValue().set("redisTemplate","redisTemplate");
        Object ret = stringRedisTemplate.opsForValue().get("redisTemplate");
        return ret;
    }*/
    @RequestMapping("/lock")
    public Object lock(){
        RedisAtomicClient redisAtomicClient = new RedisAtomicClient(redisTemplate);
        Long lock = redisAtomicClient.lock("lock:2", "lock:2:value");

        //String ret = stringRedisTemplate.opsForValue().get("lock:2");
        if(lock == 1){
            logger.info("加锁成功！准备获取数据");
            Object ret = redisTemplate.opsForValue().get("lock:2");
            logger.info("获取数据为：" + ret + ",准备再次加锁");
            Long lock2 = redisAtomicClient.lock("lock:2", "lock:2:value");
            logger.info("加锁结果：" + lock);
            if (lock2 == 0) {
                logger.info("加锁失败：" + lock + "，准备解锁");
                redisAtomicClient.unlock("lock:2", "lock:2:value");
            }
        }
        Object ret = redisTemplate.opsForValue().get("lock:2");
        return lock.toString() + "," + ret;
    }

    @RequestMapping("/getLock")
    public Object getLock(){
        RedisAtomicClient redisAtomicClient = new RedisAtomicClient(redisTemplate);
        RedisLock lock = redisAtomicClient.getLock("lock:1", 20L, 5, 2000L);
        String getValue1 = stringRedisTemplate.opsForValue().get("lock1");
        stringRedisTemplate.opsForValue().set("lock:1", "lock:1");
        lock.unlock();
        stringRedisTemplate.opsForValue().set("lock:1", "lock:1");
        String getValue2 = stringRedisTemplate.opsForValue().get("lock1");

        return getValue1 + "," + getValue2;
    }
    /** -----------------springboot redis 配置测试结束----------------- */

    /** -------------------string相关操作开始------------------- */
    /**
     * 结构存储的值:以是字符串、整数或者浮点数。
     * 结构的读写能力：对整个字符串或者字符串的其中一部分执行操作，对象和浮点数执行自增(increment)或者自减(decrement)。
     */
    @RequestMapping("/string")
    public Object redisString(){
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        //-------------------------set start---------------------------------------
        //设置指定key的值
        opsForValue.set(STRING_KEY,STRING_VALUE);
        String status = stringRedisTemplate.execute(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection redisConnection) throws DataAccessException {
                Jedis jedis = (Jedis) redisConnection.getNativeConnection();
                String status = jedis.set("SETNX", "1", "nx", "ex", 1);
                return status;
            }
        });
        if ("OK".equals(status)) {

        }
        //设置指定位置上的ASCII码
        Boolean aBoolean2 = opsForValue.setBit(STRING_KEY, 1, true);
        //将值value关联到key，并设置key过期时间
        opsForValue.set(STRING_KEY, STRING_VALUE, 5, TimeUnit.SECONDS);
        //只有在 key 不存在时设置 key 的值
        Boolean aBoolean1 = opsForValue.setIfAbsent(STRING_KEY, STRING_VALUE);
        //用value覆写key的值，从偏移量offset开始(sstring.key.value1)
        opsForValue.set(STRING_KEY,STRING_VALUE,1);
        Map<String, String> param = new HashMap<>();
        String put = param.put(STRING_KEY, STRING_VALUE);
        //批量添加
        opsForValue.multiSet(param);
        //批量添加，仅当所有key都不存在
        Boolean aBoolean = opsForValue.multiSetIfAbsent(param);
        //-------------------------set end---------------------------------------

        //-------------------------get start---------------------------------------
        //获取指定key的值
        String s1 = opsForValue.get(STRING_KEY);
        //返回key中字符串值的子字符
        String s = opsForValue.get(STRING_KEY, 1, 2);
        //将key的值设为value，并返回key旧值
        String andSet = opsForValue.getAndSet(STRING_KEY, STRING_VALUE);
        //对key所储存的值，获取指定位置上的bit
        Boolean bit = opsForValue.getBit(STRING_KEY, 2);
        //批量获取
        List<String> strings = opsForValue.multiGet(Arrays.asList(STRING_KEY, STRING_KEY + "1"));
        //-------------------------get end---------------------------------------

        //-------------------------other start---------------------------------------
        //追加到末尾
        opsForValue.append(STRING_KEY, STRING_VALUE);
        opsForValue.set(STRING_NUM_KEY, STRING_NUM_VALUE);
        //增加(自增长), 负数则为自减
        Long increment = opsForValue.increment(STRING_NUM_KEY, 1);
        //增加(自增长), 负数则为自减
        Double increment1 = opsForValue.increment(STRING_NUM_KEY, 5.5);
        //获取字符串的长度
        Long size = opsForValue.size(STRING_NUM_KEY);
        //-------------------------other end---------------------------------------
        return null;
    }
    /** -------------------string相关操作结束------------------- */
    /** -------------------keys相关操作开始------------------- */
    /**
     * 结构存储的值:一个链表，链表上的每个节点都包含了一个字符串。
     * 结构的读写能力：从链表的两端推入或者弹出元素，根据偏移量(offset)对链表进行修剪(trim)，读取单个或者多个元素，根据值来查找或者移除元素。
     */
    /** -------------------keys相关操作结束------------------- */
    /** -------------------list相关操作开始------------------- */
    /**
     * 结构存储的值:一个链表，链表上的每个节点都包含了一个字符串。
     * 结构的读写能力：从链表的两端推入或者弹出元素，根据偏移量(offset)对链表进行修剪(trim)，读取单个或者多个元素，根据值来查找或者移除元素。
     */
    /** -------------------list相关操作结束------------------- */
    /** -------------------hash相关操作开始------------------- */
    /**
     * 结构存储的值:包含键值对的无序散列表。
     * 结构的读写能力：添加、获取、移除单个键值对，获取所有键值对。
     */
    /** -------------------hash相关操作结束------------------- */
    /** -------------------set相关操作开始------------------- */
    /**
     * 结构存储的值:包含字符串的无序收集器(unOrderedCollection)，并且被包含的每个字符串都是独一无二的、各不相同。
     * 结构的读写能力：添加、获取、移除单个元素，检查一个元素是否存在于某个集合中，计算交集、并集、差集，从集合里面随机获取元素。
     */
    /** -------------------set相关操作结束------------------- */
    /** -------------------zset相关操作开始------------------- */
    /**
     * 结构存储的值:字符串成员(member)与浮点数分值(score)之间的有序映射，元素的排列顺序由分值(score)的大小决定。
     * 结构的读写能力：添加、获取、删除单个元素，根据分值(score)范围(range)或者成员来获取元素。
     */
    /** -------------------zset相关操作结束------------------- */
}
